Skip to content

managed-fund: test the price feed and recipient errors, and check quasar withdraw's USDC recipient - #214

Open
mikemaccana wants to merge 2 commits into
mainfrom
claude/peaceful-ptolemy-oh26c8-managed-fund-error-tests
Open

mikemaccana wants to merge 2 commits into
mainfrom
claude/peaceful-ptolemy-oh26c8-managed-fund-error-tests

Conversation

@mikemaccana

Copy link
Copy Markdown
Collaborator

Tests for errors nothing triggered

No test raised InvalidPriceFeed, NegativePrice, StalePriceFeed or InvalidRecipient. Each check now has a test. Every test asserts the exact error and that no tokens or shares moved, and most then show the honest path succeeding.

These tests are in anchor-v1, anchor and quasar:

  • test_wrong_price_feed_rejected: TSLAx's fresh, fully verified feed in NVDAx's place fails a deposit and a rebalance with InvalidPriceFeed.
  • test_truncated_price_feed_rejected: a price account cut to 125 bytes, too short for a Pyth price update, fails with InvalidPriceFeed.
  • test_non_positive_price_rejected: prices of zero and of -$180 fail with NegativePrice.
  • test_stale_price_rejected: a price 61 seconds old fails with StalePriceFeed, and one exactly 60 seconds old is accepted.
  • test_withdraw_rejects_recipient_owned_by_someone_else and test_withdraw_rejects_recipient_for_another_mint both fail with InvalidRecipient.

These are in quasar only:

  • test_deposit_rejects_share_account_owned_by_someone_else
  • test_collect_fees_rejects_share_account_owned_by_someone_else

Both fail with InvalidRecipient. The Anchor versions enforce the same rule through associated token account constraints, so they raise a constraint error rather than InvalidRecipient.

The test helper do_withdraw now goes through a new withdraw_to builder, so tests can name the recipients. The READMEs list the new tests, and each version's CHANGELOG.md has an entry.

Fix: quasar withdraw checks the USDC recipient

Quasar's withdraw checked that each asset leg is paid to an account the holder owns for that asset's mint. It paid the USDC leg to whatever user_usdc_account the caller named, while the Anchor versions require the holder's own USDC associated token account.

It now checks that account's owner and mint, and fails with InvalidRecipient if either is wrong. test_withdraw_rejects_usdc_recipient_owned_by_someone_else covers it.

Testing

  • cargo test passes:
    • anchor-v1: 44 tests (was 38)
    • anchor: 44 (was 38)
    • quasar managed-fund: 32 (was 23)
    • quasar mock router: 2
  • Each test fails without its check. For each test, the check was removed from the program, the program rebuilt, and the test failed. That includes the new quasar USDC recipient check: without it, the test's withdrawal succeeds. The programs were restored afterwards.
  • One exception, quasar's truncated-feed test: removing only the length check leaves it passing. That's because the program's byte readers also return InvalidPriceFeed when a read runs past the end. It fails once both are removed.

Not tested: the Anchor versions also map conversion failures after the length check to InvalidPriceFeed. Those can't fire once the length check has passed.


Generated by Claude Code

Mike MacCana added 2 commits November 10, 2026 17:03
No test triggered InvalidPriceFeed, NegativePrice, StalePriceFeed or
InvalidRecipient. Each check now has a test that asserts the exact error and
that no tokens or shares moved, then shows the honest path succeeds:

- another asset's price feed, in a deposit and a rebalance (InvalidPriceFeed)
- a price account too short for a Pyth price update (InvalidPriceFeed)
- a price of zero and a negative price (NegativePrice)
- a price 61 seconds old, refused, and one 60 seconds old, accepted
  (StalePriceFeed)
- a withdrawal paying an asset to someone else's account, or to an account for
  another mint (InvalidRecipient)
- quasar only, where these checks raise InvalidRecipient: a deposit or a fee
  collection minting shares to someone else's share account

Applied to anchor-v1, anchor and quasar. With each check removed from the
program, its test fails.

Claude-Session: https://claude.ai/code/session_01GZHin6BQpAqf7j2ucSZWkx
withdraw checked that each asset leg is paid to an account the holder owns for
that asset's mint, but paid the USDC leg to whatever user_usdc_account the
caller named. The Anchor versions require it to be the holder's USDC associated
token account. The quasar version now checks its owner and mint, failing with
InvalidRecipient, and test_withdraw_rejects_usdc_recipient_owned_by_someone_else
checks it; without the check the test's withdrawal succeeds.

Claude-Session: https://claude.ai/code/session_01GZHin6BQpAqf7j2ucSZWkx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant